package com.imachen.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.imachen.ymcc.constants.RedisSmsConstants;
import com.imachen.ymcc.domain.MessageBlack;
import com.imachen.ymcc.domain.MessageSms;
import com.imachen.ymcc.dto.RedisSmsDto;
import com.imachen.ymcc.dto.SmsCodeDto;
import com.imachen.ymcc.enums.GlobalExceptionCode;
import com.imachen.ymcc.properties.SmsRegisterProperties;
import com.imachen.ymcc.service.IMessageBlackService;
import com.imachen.ymcc.service.IMessageSmsService;
import com.imachen.ymcc.service.IVerifyService;
import com.imachen.ymcc.util.AssertUtil;
import com.imachen.ymcc.util.StrUtils;
import com.imachen.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyServiceImpl implements IVerifyService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    // 业务高度封装
    @Autowired
    private IMessageSmsService messageSmsService;

    @Autowired
    private SmsRegisterProperties smsRegisterProperties;

    @Autowired
    private IMessageBlackService messageBlackService;

    @Override
    public String imageCode(String imageCodeKey) {
        //生成图形验证码
        String code = StrUtils.getComplexRandomString(4);
        // 保存到redis
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);
        // 使用工具类生成图形验证码编码之后的base64字符串
        String base64Str = VerifyCodeUtils.verifyCode(110, 40, code);

        return base64Str;
    }


/*    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        String imageCode = smsCodeDto.getImageCode();
        String phone = smsCodeDto.getMobile();
        //1.空值校验
        if (StringUtils.isEmpty(phone)) {
            throw new GlobalCustomException(GlobalExceptionCode.PHONE_IS_NULL_ERROR);
        }
        if (StringUtils.isEmpty(imageCode)) {
            throw new GlobalCustomException(GlobalExceptionCode.IMAGECODE_IS_NULL_ERROR);
        }
        if(StringUtils.isEmpty(imageCodeKey)){
            throw new GlobalCustomException(GlobalExceptionCode.IMAGECODEKEY_ERROR);
        }

        //二：校验 - 校验图形验证码是否过期 和 是否正确
        Object obj = redisTemplate.opsForValue().get(imageCodeKey);
        if (obj==null){
            throw new GlobalCustomException(GlobalExceptionCode.IMAGECODE_EXPIRED_ERROR);
        }
        if (!obj.toString().equalsIgnoreCase(imageCode)){
            throw new GlobalCustomException(GlobalExceptionCode.IMAGECODE_ERROR);
        }
        // 三.拼接业务键，去Redis中查询Code
        String rediskey = "register:" + phone;
        Object codeObj = redisTemplate.opsForValue().get(rediskey);
        Date date = new Date();
        String code = "";
        if (codeObj != null) {
            //1.获取时间戳，判断是否过重发时间
            String[] split = codeObj.toString().split(":");
            Long time = Long.valueOf(split[1]);
            // 2.判断是否过了1分钟，如果小于那么说明没超过，提示用户
            if (date.getTime() - time < 6000){
                throw new GlobalCustomException(GlobalExceptionCode.OPERATING_FREQUENTLY_ERROR);
            }
            // 3.如果超过一分钟，那么继续沿用之前的code
            code = split[0];
        }else {
            // 如果不存在，生成新的验证码
            code = StrUtils.getRandomString(6);
        }
        // 4.将code+time存入到redis中
        redisTemplate.opsForValue().set(rediskey,code + ":" + date.getTime(),300000,TimeUnit.MILLISECONDS);
        // 5.存储消息发送日志
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("手机注册验证码");
        messageSms.setContent("您的验证码为" + code + ", 请在 5 分钟内使用");
        messageSms.setSendTime(date);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        messageSms.setIp(ip);
        messageSmsService.insert(messageSms);
        // 6.发送短信验证码
        log.info("您的验证码为" + code + ", 请在 5 分钟内使用");
    }*/


    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        String imageCodeKey = smsCodeDto.getImageCodeKey();
        String imageCode = smsCodeDto.getImageCode();
        String phone = smsCodeDto.getMobile();
        //1.空值校验 断言：spring给我们提供了断言类  isNull：我断言你为null，你如果不是null就报错
        AssertUtil.isPhone(phone,GlobalExceptionCode.PHONE_IS_NULL_ERROR);
        AssertUtil.isNotEmpty(imageCode,GlobalExceptionCode.IMAGECODE_IS_NULL_ERROR);
        AssertUtil.isNotEmpty(imageCodeKey,GlobalExceptionCode.IMAGECODEKEY_ERROR);

        //二：校验 - 校验图形验证码是否过期 和 是否正确
        Object obj = redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isNotNull(obj,GlobalExceptionCode.IMAGECODE_EXPIRED_ERROR);

        boolean b = obj.toString().equalsIgnoreCase(imageCode);
        AssertUtil.isTrue(b,GlobalExceptionCode.IMAGECODE_ERROR);

        // 检验⿊名单  拼接业务键
        List<MessageBlack> messageBlacks = messageBlackService.selectList(null);
        String blackRediskey = String.format(RedisSmsConstants.REDIS_REGISTER_BLACK_KEY, messageBlacks);
        Object blackObj = redisTemplate.opsForValue().get(blackRediskey);
        AssertUtil.isNull(blackObj,GlobalExceptionCode.SMS_BLACK_ERROR);

        // 三.拼接业务键，去Redis中查询Code  register:%s ，把你的%s替换成你的phone
        String rediskey = String.format(RedisSmsConstants.REDIS_REGISTER_PHONE_KEY,phone);
        Object codeObj = redisTemplate.opsForValue().get(rediskey);
        Date date = new Date();
        String code = "";
        if (codeObj != null) {
            //1.获取时间戳，判断是否过重发时间
            RedisSmsDto redisSmsDto = (RedisSmsDto) codeObj;
            // 2.判断是否过了1分钟，如果小于那么说明没超过，提示用户
            boolean boo = (date.getTime() - redisSmsDto.getTime()) < smsRegisterProperties.getInterval();
            AssertUtil.isFalse(boo,GlobalExceptionCode.OPERATING_FREQUENTLY_ERROR);
            // 3.如果超过一分钟，那么继续沿用之前的code
            code = redisSmsDto.getCode();
        }else {
            // 如果不存在，生成新的验证码
            code = StrUtils.getRandomString(6);
        }

        // 4.将code+time存入到redis中
        RedisSmsDto redisSmsDto = new RedisSmsDto(code, date.getTime());
        redisTemplate.opsForValue().set(rediskey, redisSmsDto, smsRegisterProperties.getExpiredtime(), TimeUnit.MILLISECONDS);
        // 5.存储消息发送日志
        sendMessageSms(date, code, phone);
    }

    private void sendMessageSms(Date date, String code, String phone) {
        // 5.存储消息发送日志
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(smsRegisterProperties.getTitle());
        String content = String.format(smsRegisterProperties.getContent(), code);
        messageSms.setContent(content);
        messageSms.setSendTime(date);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String ip = request.getRemoteAddr();
        messageSms.setIp(ip);
        messageSms.setPhone(phone);
        messageSmsService.insert(messageSms);
        // 6.发送短信验证码
        log.info(content);
    }


}
